package com.example.android.BluetoothChat;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class BluetoothTextServer {
	private final BluetoothAdapter mAdapter;
	private final Handler mHandler;
	private AcceptThread mSecureAcceptThread;
	private int mState;
	// Constants that indicate the current connection state
	public static final int STATE_NONE = 0; // we're doing nothing
	public static final int STATE_LISTEN = 1; // now listening for incoming
	public static final String NAME_SECURE = "BluetoothChatSecure";
	public static final UUID MY_UUID_SECURE = UUID
			.fromString("0591e450-c99a-11e2-8b8b-0800200c9a66");
	private static final String TAG = "BluetoothServer";
	/**
	 * 已经建立连接的客户端处理者集合
	 */
	public HashMap<String, ClientConnectHandler> mBluetoothClientHandlerMap;

	// private Context context;

	public BluetoothTextServer(Context context, Handler handler) {
		mAdapter = BluetoothAdapter.getDefaultAdapter();
		mState = STATE_NONE;
		mHandler = handler;
		// this.context = context;

	}

	public void setUpServer() {
		// If the adapter is null, then Bluetooth is not supported
		if (mAdapter == null) {
			SendMessageToUI("Bluetooth is not be supported, please exit app");
			return;
		}
		if (!mAdapter.isEnabled()) {
			SendMessageToUI("Bluetooth is not isEnabled, please trun on and set Discoveryable");
			return;
		}
		mSecureAcceptThread = new AcceptThread();
		mBluetoothClientHandlerMap = new HashMap<String, ClientConnectHandler>();
		mSecureAcceptThread.start();
		mState = STATE_LISTEN;
	}

	private class AcceptThread extends Thread {
		// The local server socket
		private final BluetoothServerSocket mmServerSocket;
		private String mSocketType;

		public AcceptThread() {
			BluetoothServerSocket tmp = null;
			mSocketType = "Secure";
			// Create a new listening server socket
			try {

				tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
						MY_UUID_SECURE);
				SendMessageToUI("BluetoothMessageServer has setup ");
			} catch (IOException e) {
				Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
			}
			mmServerSocket = tmp;
		}

		public void run() {
			Log.d(TAG, "waiting connnect for client " + this);
			setName("AcceptThread" + mSocketType);

			BluetoothSocket socket = null;

			// Listen to the server socket if we're not connected
			while (mState != STATE_NONE) {
				try {
					// This is a blocking call and will only return on a
					// successful connection or an exception
					SendMessageToUI("waiting for client");
					socket = mmServerSocket.accept();
					Log.d(TAG, "receive a connect request" + this);
					SendMessageToUI("receive a connect request");
					sleep(2000);
				} catch (IOException e) {
					Log.e(TAG, "Socket Type: " + mSocketType
							+ "accept() failed", e);
					break;
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				// If a connection was accepted
				if (socket != null) {
					// Situation normal. Start the connected thread.
					connect(socket, socket.getRemoteDevice());
					SendMessageToUI("client num"
							+ mBluetoothClientHandlerMap.size());
				}
			}
			Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);

		}

		public void cancel() {
			Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
			try {
				mmServerSocket.close();
			} catch (IOException e) {
				Log.e(TAG, "Socket Type" + mSocketType
						+ "close() of server failed", e);
			}
		}
	}

	public synchronized void connect(BluetoothSocket socket,
			BluetoothDevice device) {
		Log.d(TAG, "connect, Socket Type:" + device.getName());
		// Start the thread to manage the connection and perform transmissions
		ClientConnectHandler mConnectedThread = new ClientConnectHandler(
				socket, device.getName());
		mConnectedThread.start();
		mBluetoothClientHandlerMap.put(device.getName(), mConnectedThread);
	}

	private class ClientConnectHandler extends Thread {
		private final BluetoothSocket mmSocket;
		private final InputStream mmInStream;
		private final OutputStream mmOutStream;
		private boolean state = true;
		private String name;

		public ClientConnectHandler(BluetoothSocket socket, String name) {
			Log.d(TAG, "create ClientConnectHandler: ");
			mmSocket = socket;
			InputStream tmpIn = null;
			OutputStream tmpOut = null;
			this.name = name;
			// Get the BluetoothSocket input and output streams
			try {
				tmpIn = socket.getInputStream();
				tmpOut = socket.getOutputStream();
			} catch (IOException e) {
				Log.e(TAG, "temp sockets not created", e);
			}

			mmInStream = tmpIn;
			mmOutStream = tmpOut;
		}

		public void run() {
			Log.i(TAG, "BEGIN mConnectedThread");
			byte[] buffer = new byte[1024];
			int bytes;

			// Keep listening to the InputStream while connected
			while (state) {
				try {
					// Read from the InputStream
					bytes = mmInStream.read(buffer);

					// Send the obtained bytes to the UI Activity
					mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes,
							-1, buffer).sendToTarget();
				} catch (IOException e) {
					Log.e(TAG, "disconnected", e);
					break;
				}
			}
		}

		/**
		 * Write to the connected OutStream.
		 * 
		 * @param buffer
		 *            The bytes to write
		 */
		public void write(byte[] buffer, int offset, int count) {
			try {
				mmOutStream.write(buffer, offset, count);
				// Share the sent message back to the UI Activity
				// mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1,
				// buffer)
				// .sendToTarget();
			} catch (IOException e) {
				Log.e(TAG, "Exception during write", e);
			}
		}

		public void cancel() {
			try {
				state = false;
				mmSocket.close();
				SendMessageToUI("cancel connect to" + name);
			} catch (IOException e) {
				Log.e(TAG, "close() of connect socket failed", e);

			}
		}
	}

	public void SendMessageToUI(String string) {
		Message msg = new Message();
		msg.what = 0;
		msg.obj = string;
		mHandler.sendMessage(msg);
		// Message msg =
		// mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
		// Bundle bundle = new Bundle();
		// bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
		// msg.setData(bundle);
		// mHandler.sendMessage(msg);
	}

	public void SendCommandToUI(String string) {
		Message msg = new Message();
		msg.what = 1;
		msg.obj = string;
		mHandler.sendMessage(msg);
	}

	public void stop() {
		if (null != mSecureAcceptThread) {
			mState = STATE_NONE;
			mSecureAcceptThread.cancel();
		}
		// TODO 停止所有的客户端连接
	}

	public void sendTextToAllClient(final String message) {
		new Thread() {
			@Override
			public void run() {
				Iterator<Entry<String, ClientConnectHandler>> iter = mBluetoothClientHandlerMap
						.entrySet().iterator();
				ArrayList<ClientConnectHandler> list = new ArrayList<BluetoothTextServer.ClientConnectHandler>();
				while (iter.hasNext()) {
					Map.Entry<String, ClientConnectHandler> entry = (Map.Entry<String, ClientConnectHandler>) iter
							.next();
					String key = entry.getKey();
					SendMessageToUI("send message to " + key);
					ClientConnectHandler val = entry.getValue();
					list.add(val);
				}
				byte[] buffer = message.getBytes();
				SendMessageToUI(":" + message);
				for (ClientConnectHandler c : list) {
					c.write(buffer, 0, buffer.length);
				}
			}
		}.start();
	}
}
